package com.musicsonar.android.adapter;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.Checkable;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;

import com.musicsonar.android.activity.MusicSonarActivity;
import com.musicsonar.android.activity.PlayListActivity;
import com.musicsonar.android.activity.R;
import com.musicsonar.android.activity.TabPlayListActivity;
import com.musicsonar.android.utils.MusicSonarConstant;
import com.musicsonar.android.utils.MusicSonarUtils;
import com.musicsonar.android.utils.SongsManager;
import com.musicsonar.android.utils.WebImage;

@SuppressLint("UseValueOf")
public class ResultSearchAdapter extends BaseAdapter implements Filterable {

	private int[] mTo;
	private String[] mFrom;
	private ViewBinder mViewBinder;

	private List<Map<String, Object>> mData;

	private int mResource;
	private int mDropDownResource;
	private LayoutInflater mInflater;

	private SimpleFilter mFilter;

	private ArrayList<Map<String, ?>> mUnfilteredData;
	private String mURLQuery;

	private boolean mSaveImage;

	public ResultSearchAdapter(Context context, String url_query, List<Map<String, Object>> initData, int resource, String[] from, int[] to, boolean saveImage) {
		mURLQuery = url_query;
		mResource = mDropDownResource = resource;
		mFrom = from;
		mTo = to;
		mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		mSaveImage = saveImage;
		// Filling information
		fillDataInformation(initData);
	}

	public ResultSearchAdapter(Context context, List<Map<String, Object>> data, int resource, String[] from, int[] to, boolean saveImage) {
		mData = data;
		mResource = mDropDownResource = resource;
		mFrom = from;
		mTo = to;
		mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		mSaveImage = saveImage;
	}

	public int getCount() {
		if(mData != null){
			return mData.size();
		}else{
			return -1;
		}
	}

	public List<Map<String, Object>> getData(){
		return mData;
	}

	public String getURLQuery(){
		return mURLQuery;
	}

	public Object getItem(int position) {
		return mData.get(position);
	}

	public long getItemId(int position) {
		return position;
	}

	public View getView(int position, View convertView, ViewGroup parent) {
		return createViewFromResource(position, convertView, parent, mResource);
	}

	private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) {
		View v;
		if (convertView == null) {
			v = mInflater.inflate(resource, parent, false);

			final int[] to = mTo;
			final int count = to.length;
			final View[] holder = new View[count];

			for (int i = 0; i < count; i++) {
				holder[i] = v.findViewById(to[i]);
			}
			v.setTag(holder);
		} else {
			v = convertView;
		}

		bindView(position, v);

		return v;
	}

	public void setDropDownViewResource(int resource) {
		this.mDropDownResource = resource;
	}

	public View getDropDownView(int position, View convertView, ViewGroup parent) {
		return createViewFromResource(position, convertView, parent, mDropDownResource);
	}

	private void bindView(int position, View view) {
		final Map<String, ?> dataSet = mData.get(position);
		if (dataSet == null) {
			return;
		}

		final ViewBinder binder = mViewBinder;
		final View[] holder = (View[]) view.getTag();
		final String[] from = mFrom;
		final int[] to = mTo;
		final int count = to.length;

		for (int i = 0; i < count; i++) {
			final View v = holder[i];
			if (v != null) {
				final Object data = dataSet.get(from[i]);
				String text = data == null ? "" : data.toString();
				if (text == null) {
					text = "";
				}

				boolean bound = false;
				if (binder != null) {
					bound = binder.setViewValue(v, data, text);
				}

				if (!bound) {
					if (v instanceof Checkable) {
						if (data instanceof Boolean) {
							((Checkable) v).setChecked((Boolean) data);
						}if (data instanceof Integer) {
							setCheckControl((CheckBox) v, (Integer) data);
						} else {
							throw new IllegalStateException(v.getClass().getName() + " should be bound to a Boolean, not a " + data.getClass());
						}
					} else if (v instanceof ImageButton) {
						setImageButton((ImageButton) v, text);
					} else if (v instanceof TextView) {
						setViewText((TextView) v, text);
					} else if (v instanceof ImageView) {
						if (data instanceof Integer) {
							setViewImage((ImageView) v, (Integer) data);
						} else {
							setViewImage((ImageView) v, text);
						}
					} else {
						throw new IllegalStateException(v.getClass().getName() + " is not a " + " view that can be bounds by this SimpleAdapter");
					}
				}
			}
		}
	}

	public ViewBinder getViewBinder() {
		return mViewBinder;
	}

	public void setViewBinder(ViewBinder viewBinder) {
		mViewBinder = viewBinder;
	}

	public void setViewImage(ImageView v, int value) {
		v.setImageResource(value);
	}

	public void setViewImage(ImageView v, String value) {
		try {
			v.setImageResource(Integer.parseInt(value));
		} catch (NumberFormatException nfe) {
			if(value.startsWith("http")){
				WebImage mp = new WebImage(v, value, WebImage.LIST, mSaveImage);
				mp.execute("");
			}else{
				v.setImageURI(Uri.parse(value));
			}
		}
	}

	public void setImageButton(ImageButton v, String text) {
		if(v.getId() == R.id.btnPlaySong){
			v.setOnClickListener(new PlayOnClickListener(text));
		}else{
			if(v.getId() == R.id.btnDeleteSong){
				v.setOnClickListener(new DeleteOnClickListener(text));
			}
		}
	}

	public void setCheckControl(CheckBox v, Integer data){
		Map<?, ?> toDraw = (Map<?, ?>)mData.get(data);
		Boolean isChecked = (Boolean)toDraw.get("songSelected");
		v.setChecked(isChecked != null ? isChecked : false);
		v.setOnClickListener(new SelectedOnClickListener(v, data));
	}

	public void setViewText(TextView v, String text) {
		v.setText(text);
	}

	public Filter getFilter() {
		if (mFilter == null) {
			mFilter = new SimpleFilter();
		}
		return mFilter;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void fillDataInformation(List initData){
		try{
			if(mURLQuery != null && !"".equals(mURLQuery)){
				Map<String, Object> data = executeURL(mURLQuery, initData);
				if(initData == null){
					initData = (List<? extends Map<String, ?>>) data.get("resultList");
				}else{
					initData.addAll((List<? extends Map<String, ?>>) data.get("resultList"));
				}
				mData = initData;
				mURLQuery = (String) data.get("next");
			}
		}catch(Exception e){}
	}

	public static interface ViewBinder {
		boolean setViewValue(View view, Object data, String textRepresentation);
	}

	private class SelectedOnClickListener implements View.OnClickListener{

		private CheckBox view;
		private Integer data;

		public SelectedOnClickListener(CheckBox view, Integer data){
			this.view = view;
			this.data = data;
		}

		public void onClick(View v) {
			CheckBox box = (CheckBox)view;
			((Map<String, Object>)mData.get(data)).put("songSelected", box.isChecked());
		}
		
	}

	private class PlayOnClickListener implements View.OnClickListener{

		private String valueToUse;

		public PlayOnClickListener(String valueToUse) {
			super();
			this.valueToUse = valueToUse;
		}

		@SuppressWarnings("deprecation")
		public void onClick(View view) {
			PlayListActivity activity = null;
			TabPlayListActivity father = null;
			if(view.getContext() instanceof PlayListActivity){
				activity = (PlayListActivity)view.getContext();
				father = (TabPlayListActivity) activity.getParent();
			}else{
				father = ((TabPlayListActivity)view.getContext());
				String tabTag = father.getTabHost().getCurrentTabTag();
				activity = (PlayListActivity)father.getLocalActivityManager().getActivity(tabTag); 
			}

			
			Intent intent = new Intent(activity.getBaseContext(), MusicSonarActivity.class);
			intent.putExtra("songIndex", Integer.parseInt(valueToUse));
			intent.putExtra("songsList", SongsManager.getActualPlayList());

			if(father != null){
				father.setResult(100, intent);
				father.finish();
			}else{
				activity.setResult(100,intent);
				activity.finish();				
			}
		}
		
	}

	private class DeleteOnClickListener implements View.OnClickListener{

		private String valueToUse;

		public DeleteOnClickListener(String valueToUse) {
			super();
			this.valueToUse = valueToUse;
		}

		public void onClick(View view) {
			PlayListActivity activity = (PlayListActivity)view.getContext();
        	int toDelete = Integer.parseInt(valueToUse != null ? valueToUse : "0");
        	if(toDelete != -1){
        		HashMap<String, Object> _data = (HashMap<String, Object>)activity.songsList.get(toDelete);
        		String image = (String)_data.get("songImage");
        		try{
        			(new File(MusicSonarConstant.MEDIA_PATH + MusicSonarUtils.getImageID(image) + ".jpg")).delete();
        		}catch(Exception e){
        			
        		}
        		activity.songsList.remove(toDelete);
        	}
        	for(int i = 0; i < activity.songsList.size(); i++){
        		HashMap<String, Object> _data = (HashMap<String, Object>)activity.songsList.get(i);
        		_data.put("index", String.valueOf(i));
        		activity.songsList.set(i, _data);
        	}
        	try{
        		SongsManager.savePlayList(activity.songsList);
        	}catch(Exception e){
        		e.printStackTrace();
        	}
        	ListAdapter adapter = new ResultSearchAdapter(activity, activity.songsList, R.layout.playlist_item, new String[] { "songImage", "songTitle", "songDuration", "index", "index" }, new int[] { R.id.songImage, R.id.songTitle, R.id.songDuration, R.id.btnPlaySong, R.id.btnDeleteSong }, true);
        	activity.setListAdapter(adapter);
		}
		
	}

	private class SimpleFilter extends Filter {
		protected FilterResults performFiltering(CharSequence prefix) {
			FilterResults results = new FilterResults();

			if (mUnfilteredData == null) {
				mUnfilteredData = new ArrayList<Map<String, ?>>(mData);
			}

			if (prefix == null || prefix.length() == 0) {
				ArrayList<Map<String, ?>> list = mUnfilteredData;
				results.values = list;
				results.count = list.size();
			} else {
				String prefixString = prefix.toString().toLowerCase();

				ArrayList<Map<String, ?>> unfilteredValues = mUnfilteredData;
				int count = unfilteredValues.size();

				ArrayList<Map<String, ?>> newValues = new ArrayList<Map<String, ?>>(count);

				for (int i = 0; i < count; i++) {
					Map<String, ?> h = unfilteredValues.get(i);
					if (h != null) {

						int len = mTo.length;

						for (int j=0; j<len; j++) {
							String str =  (String)h.get(mFrom[j]);

							String[] words = str.split(" ");
							int wordCount = words.length;

							for (int k = 0; k < wordCount; k++) {
								String word = words[k];

								if (word.toLowerCase().startsWith(prefixString)) {
									newValues.add(h);
									break;
								}
							}
						}
					}
				}

				results.values = newValues;
				results.count = newValues.size();
			}

			return results;
		}

		@SuppressWarnings("unchecked")
		protected void publishResults(CharSequence constraint, FilterResults results) {
			mData = (List<Map<String, Object>>) results.values;
			if (results.count > 0) {
				notifyDataSetChanged();
			} else {
				notifyDataSetInvalidated();
			}
		}
	}

	private Map<String, Object> executeURL(String url_query, List<?> initData) throws Exception{
		Map<String, Object> result = new HashMap<String, Object>();
		URL url = new URL(url_query);
		HttpURLConnection cnx = (HttpURLConnection)url.openConnection();
		cnx.setDoInput(true);
		cnx.setDoOutput(true);
		cnx.setRequestMethod("GET");
		
		InputStreamReader in = new InputStreamReader(cnx.getInputStream(), Charset.forName("UTF-8"));
		BufferedReader rd = new BufferedReader(in);
		StringBuffer xml = new StringBuffer();
		String line;
		while ((line = rd.readLine()) != null) {
			xml.append(line);
		}

		Document doc = MusicSonarUtils.XMLfromString(xml.toString());
		NodeList nodes = doc.getElementsByTagName("link");

		// Finding for previous button
		result.put("previous", "");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element element = (Element)nodes.item(i);
			String attrib = element.getAttribute("rel");
			if(attrib != null && attrib != "" && "previous".equals(attrib)){
				String link = element.getAttribute("href");
				result.put("previous", link);
				break;
			}
		}
		// Finding for next button
		result.put("next", "");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element element = (Element)nodes.item(i);
			String attrib = element.getAttribute("rel");
			if(attrib != null && attrib != "" && "next".equals(attrib)){
				String link = element.getAttribute("href");
				result.put("next", link);
				break;
			}
		}

		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		int startIndex = initData != null ? initData.size() : 0;
		// Finding for entry information
		NodeList entries = doc.getElementsByTagName("entry");
		for (int i = 0; i < entries.getLength(); i++) {
			Element element = (Element)entries.item(i);
			Element nodeTitle = (Element)element.getElementsByTagName("media:title").item(0);
			Element nodePlayer = (Element)element.getElementsByTagName("media:player").item(0);
			Element nodeThumbnail = (Element)element.getElementsByTagName("media:thumbnail").item(0);
			Element nodeContent = (Element)element.getElementsByTagName("media:content").item(0);
			Element nodeDuration = (Element)element.getElementsByTagName("yt:duration").item(0);
			String title = nodeTitle.getTextContent();
			String vid = nodePlayer.getAttribute("url");
			String img = nodeThumbnail.getAttribute("url");
			String segundos = nodeContent != null ? nodeContent.getAttribute("duration") : nodeDuration.getAttribute("seconds");
			String duracion = MusicSonarUtils.milliSecondsToTimer((new Long(segundos != null && !"".equals(segundos) ? segundos + "000" : "0")).longValue());
			Map<String, Object> item = new HashMap<String, Object>();
			item.put("index", startIndex + resultList.size());
			item.put("songTitle", title);
			item.put("songPath", vid);
			item.put("songYT", vid);
			item.put("songImage", img);
			item.put("segundos", segundos);
			item.put("songDuration", duracion);
			item.put("songSelected", Boolean.FALSE);
			resultList.add(item);
		}
		result.put("resultList", resultList);

		return result;
	}

}